package impl

import (
	"adam2/internal/domain"
	"adam2/internal/model"
	"anubis-framework/pkg/io"
	"time"
)

type StockTransactionDataAllDaoImpl struct {
	*BaseDaoImpl
}

// 返回dao实现类
func GetStockTransactionDataAllDaoImpl() *StockTransactionDataAllDaoImpl {
	return &StockTransactionDataAllDaoImpl{GetBaseDaoImpl()}
}

// 返回表名
func (_stockTransactionDataAllDaoImpl *StockTransactionDataAllDaoImpl) FindTableName() string {
	return "STOCK_TRANSACTION_DATA_ALL"
}

// 获取某一个交易日的数据
func (_stockTransactionDataAllDaoImpl *StockTransactionDataAllDaoImpl) FindByDate(date string) model.StockTransactionDataAllArray {
	var stockTransactionDataAllArray model.StockTransactionDataAllArray
	_stockTransactionDataAllDaoImpl.db.Raw("select * from stock_transaction_data_all t where t.date_ = to_date(?, 'yyyy-mm-dd')", date).Find(&stockTransactionDataAllArray)
	return stockTransactionDataAllArray
}

// 根据开始时间和结束时间，返回日期，并升序排列
func (_stockTransactionDataAllDaoImpl *StockTransactionDataAllDaoImpl) GetDistinctDateBetweenDateOrderByDateAsc(beginDate string, endDate string) ([]string, error) {
	var dateArray []string
	_stockTransactionDataAllDaoImpl.db.Raw("select distinct to_char(t.date_, 'yyyy-mm-dd') from stock_transaction_data_all t "+
		"where t.date_ between to_date(?, 'yyyy-mm-dd') and to_date(?, 'yyyy-mm-dd') "+
		"order by to_char(t.date_, 'yyyy-mm-dd') asc", beginDate, endDate).Scan(&dateArray)
	return dateArray, nil
}

// 查找某只股票，在开始时间和结束时间之间的记录，并按照日期升序排列
func (_stockTransactionDataAllDaoImpl *StockTransactionDataAllDaoImpl) GetByCodeBetweenDateOrderByDateAsc(code string, beginDate string, endDate string) (*model.StockTransactionDataAllArray, error) {
	var stockTransactionDataAllArray *model.StockTransactionDataAllArray
	_stockTransactionDataAllDaoImpl.db.Raw("select * from stock_transaction_data_all t "+
		"where t.date_ between to_date(p_begin_date, ?) and to_date(p_end_date, ?) "+
		"and t.code_ = ? "+
		"order by t.date_ asc", beginDate, endDate, code).Scan(&stockTransactionDataAllArray)
	return stockTransactionDataAllArray, nil
}

// 在开始时间和结束时间之间，按照日期分组，分别计算所有收盘价、移动平均线的平均值（经过平滑处理后的）
func (_stockTransactionDataAllDaoImpl *StockTransactionDataAllDaoImpl) GetAverageClosePriceAndMaBetweenDateGroupByDateOrderByDateAsc_smooth(beginDate string, endDate string) (*domain.AverageClosePriceAndMaBetweenDateGroupByDateOrderByDateAscArray, error) {
	var averageClosePriceAndMaBetweenDateGroupByDateOrderByDateAscArray *domain.AverageClosePriceAndMaBetweenDateGroupByDateOrderByDateAscArray
	//_stockTransactionDataAllDaoImpl.db.Raw("select to_char(t.date_, 'yyyy-mm-dd') DATE_, avg(t.close_price) AVERAGE_CLOSE_PRICE, avg(t.ma5) AVERAGE_MA5, "+
	//	"avg(t.ma10) AVERAGE_MA10, avg(t.ma20) AVERAGE_MA20, avg(t.ma60) AVERAGE_MA60, "+
	//	"avg(t.ma120) AVERAGE_MA120, avg(t.ma250) AVERAGE_MA250 "+
	//	"from stock_transaction_data_all t "+
	//	"where t.date_ between to_date(?,'yyyy-mm-dd') and to_date(?,'yyyy-mm-dd') "+
	//	"group by t.date_ "+
	//	"order by t.date_ asc", beginDate, endDate).Scan(&averageClosePriceAndMaBetweenDateGroupByDateOrderByDateAscArray)
	_stockTransactionDataAllDaoImpl.db.Raw("SELECT t1.date_, t1.AVERAGE_CLOSE_PRICE, "+
		"round(AVG(t1.AVERAGE_MA5) OVER (ORDER BY t1.date_ ROWS BETWEEN 20 PRECEDING AND CURRENT ROW), 2) AS AVERAGE_MA5, "+
		"round(AVG(t1.AVERAGE_MA10) OVER (ORDER BY t1.date_ ROWS BETWEEN 20 PRECEDING AND CURRENT ROW), 2) AS AVERAGE_MA10, "+
		"round(AVG(t1.AVERAGE_MA20) OVER (ORDER BY t1.date_ ROWS BETWEEN 20 PRECEDING AND CURRENT ROW), 2) AS AVERAGE_MA20,"+
		"round(AVG(t1.AVERAGE_MA60) OVER (ORDER BY t1.date_ ROWS BETWEEN 20 PRECEDING AND CURRENT ROW), 2) AS AVERAGE_MA60, "+
		"round(AVG(t1.AVERAGE_MA120) OVER (ORDER BY t1.date_ ROWS BETWEEN 20 PRECEDING AND CURRENT ROW), 2) AS AVERAGE_MA120, "+
		"round(AVG(t1.AVERAGE_MA250) OVER (ORDER BY t1.date_ ROWS BETWEEN 20 PRECEDING AND CURRENT ROW), 2) AS AVERAGE_MA250 "+
		"FROM ("+
		"select to_char(t.date_, 'yyyy-mm-dd') DATE_, avg(t.close_price) AVERAGE_CLOSE_PRICE, avg(t.ma5) AVERAGE_MA5, "+
		"avg(t.ma10) AVERAGE_MA10, avg(t.ma20) AVERAGE_MA20, avg(t.ma60) AVERAGE_MA60, avg(t.ma120) AVERAGE_MA120, avg(t.ma250) AVERAGE_MA250 "+
		"from stock_transaction_data_all t "+
		"where t.date_ between to_date(?,'yyyy-mm-dd') and to_date(?,'yyyy-mm-dd') "+
		"group by t.date_ "+
		"order by t.date_ asc) t1", beginDate, endDate).Scan(&averageClosePriceAndMaBetweenDateGroupByDateOrderByDateAscArray)
	return averageClosePriceAndMaBetweenDateGroupByDateOrderByDateAscArray, nil
}

// 在开始时间和结束时间之间，按照日期分组，分别计算所有收盘价、移动平均线的平均值、biash和总的成交额的平均值
func (_stockTransactionDataAllDaoImpl *StockTransactionDataAllDaoImpl) GetAverageClosePriceAndMaAndTotalTurnoverAndBiasBetweenDateGroupByDateOrderByDateAsc(beginDate string, endDate string) (*domain.AverageClosePriceAndMaAndTotalTurnoverBullShortLineByBiasArray, error) {
	var averageClosePriceAndMaAndTotalTurnoverBullShortLineByBiasArray *domain.AverageClosePriceAndMaAndTotalTurnoverBullShortLineByBiasArray
	_stockTransactionDataAllDaoImpl.db.Raw("select to_char(t.date_, 'yyyy-mm-dd') DATE_, avg(t.close_price) AVERAGE_CLOSE_PRICE, avg(t.ma5) AVERAGE_MA5, "+
		"avg(t.ma10) AVERAGE_MA10, avg(t.ma20) AVERAGE_MA20, avg(t.ma60) AVERAGE_MA60, avg(t.ma120) AVERAGE_MA120, avg(t.ma250) AVERAGE_MA250, "+
		"avg(t.bias5) AVERAGE_BIAS5, avg(t.bias10) AVERAGE_BIAS10, avg(t.bias20) AVERAGE_BIAS20, avg(t.bias60) AVERAGE_BIAS60, "+
		"avg(t.bias120) AVERAGE_BIAS120, avg(t.bias250) AVERAGE_BIAS250, sum(t.turnover) TOTAL_TURNOVER "+
		"from stock_transaction_data_all t "+
		"where t.date_ between to_date(?,'yyyy-mm-dd') and to_date(?,'yyyy-mm-dd') "+
		"group by t.date_ "+
		"order by t.date_ asc", beginDate, endDate).Scan(&averageClosePriceAndMaAndTotalTurnoverBullShortLineByBiasArray)
	return averageClosePriceAndMaAndTotalTurnoverBullShortLineByBiasArray, nil
}

// 判断当前交易日，所有股票的平均年线是否单调不递减(平均年线只保留小数点后1位)
func (_stockTransactionDataAllDaoImpl *StockTransactionDataAllDaoImpl) IsAverageMa250NotDecrement(date string, notDecrementDateNumber int) bool {
	io.Infoln("判断当前交易日[%s]，所有股票的平均年线在[%d]天内，是否单调不递减(平均年线只保留小数点后1位)", date, notDecrementDateNumber)

	var averageClosePriceAndMaBetweenDateGroupByDateOrderByDateAscArray domain.AverageClosePriceAndMaBetweenDateGroupByDateOrderByDateAscArray
	_stockTransactionDataAllDaoImpl.db.Raw("select * from ("+
		"select to_char(t.date_,'yyyy-mm-dd') DATE_, round(avg(t.ma250), 1) AVERAGE_MA250 "+
		"from stock_transaction_data_all t "+
		"where t.date_ between to_date(?,'yyyy-mm-dd')-60 and to_date(?,'yyyy-mm-dd') group by t.date_ order by t.date_ desc) "+
		"where rownum<=?", date, date, notDecrementDateNumber).Scan(&averageClosePriceAndMaBetweenDateGroupByDateOrderByDateAscArray)

	var realDateNumber int = len(averageClosePriceAndMaBetweenDateGroupByDateOrderByDateAscArray)
	if realDateNumber == notDecrementDateNumber {
		var previous *domain.AverageClosePriceAndMaBetweenDateGroupByDateOrderByDateAsc
		for index, value := range averageClosePriceAndMaBetweenDateGroupByDateOrderByDateAscArray {
			if index == 0 {
				previous = value
				continue
			} else {
				if value.AverageMa250 > previous.AverageMa250 {
					io.Infoln("日期[%s]，所有股票的平均年线单调递减", date)
					return false
				} else {
					previous = value
				}
			}
		}
		io.Infoln("判断当前交易日[%s]，所有股票的平均年线在[%d]天内，单调不递减", date, notDecrementDateNumber)
		return true
	} else {
		io.Infoln("日期[%s]之前的交易记录数为[%d]，小于[%d]，无法判断所有股票的平均年线是否是单调不递减，所以按照不是单调递减处理", date, realDateNumber, notDecrementDateNumber)
		return false
	}
}

// 判断当前交易日，所有股票的平均年线是否单调不递减(平均年线只保留小数点后2位，并做了平滑处理，时间窗口为20)
func (_stockTransactionDataAllDaoImpl *StockTransactionDataAllDaoImpl) IsAverageMa250NotDecrement_smooth(date string, notDecrementDateNumber int) bool {
	io.Infoln("判断当前交易日[%s]，所有股票的平均年线在[%d]天内，是否单调不递减(平均年线只保留小数点后2位，并做了平滑处理，时间窗口为20)", date, notDecrementDateNumber)

	var averageClosePriceAndMaBetweenDateGroupByDateOrderByDateAscArray *domain.AverageClosePriceAndMaBetweenDateGroupByDateOrderByDateAscArray
	_stockTransactionDataAllDaoImpl.db.Raw("SELECT t1.date_, t1.AVERAGE_CLOSE_PRICE, "+
		"round(AVG(t1.AVERAGE_MA5) OVER (ORDER BY t1.date_ desc ROWS BETWEEN 20 PRECEDING AND CURRENT ROW), 2) AS AVERAGE_MA5, "+
		"round(AVG(t1.AVERAGE_MA10) OVER (ORDER BY t1.date_ desc ROWS BETWEEN 20 PRECEDING AND CURRENT ROW), 2) AS AVERAGE_MA10, "+
		"round(AVG(t1.AVERAGE_MA20) OVER (ORDER BY t1.date_ desc ROWS BETWEEN 20 PRECEDING AND CURRENT ROW), 2) AS AVERAGE_MA20,"+
		"round(AVG(t1.AVERAGE_MA60) OVER (ORDER BY t1.date_ desc ROWS BETWEEN 20 PRECEDING AND CURRENT ROW), 2) AS AVERAGE_MA60, "+
		"round(AVG(t1.AVERAGE_MA120) OVER (ORDER BY t1.date_ desc ROWS BETWEEN 20 PRECEDING AND CURRENT ROW), 2) AS AVERAGE_MA120, "+
		"round(AVG(t1.AVERAGE_MA250) OVER (ORDER BY t1.date_ desc ROWS BETWEEN 20 PRECEDING AND CURRENT ROW), 2) AS AVERAGE_MA250 "+
		"FROM ("+
		"select to_char(t.date_, 'yyyy-mm-dd') DATE_, avg(t.close_price) AVERAGE_CLOSE_PRICE, avg(t.ma5) AVERAGE_MA5, "+
		"avg(t.ma10) AVERAGE_MA10, avg(t.ma20) AVERAGE_MA20, avg(t.ma60) AVERAGE_MA60, avg(t.ma120) AVERAGE_MA120, avg(t.ma250) AVERAGE_MA250 "+
		"from stock_transaction_data_all t "+
		"where t.date_ between add_months(to_date(?,'yyyy-mm-dd'), -24) and to_date(?,'yyyy-mm-dd') "+
		"group by t.date_ "+
		"order by t.date_ desc) t1", date, date).Scan(&averageClosePriceAndMaBetweenDateGroupByDateOrderByDateAscArray)

	var originNotDecrementDateNumber int = notDecrementDateNumber
	if len(*averageClosePriceAndMaBetweenDateGroupByDateOrderByDateAscArray) < notDecrementDateNumber {
		io.Infoln("当前记录数不足[%d]个，按照不是单调不递减处理", originNotDecrementDateNumber)
		return false
	} else {
		var last float64 = 0
		for index, averageClosePriceAndMaBetweenDateGroupByDateOrderByDateAsc := range *averageClosePriceAndMaBetweenDateGroupByDateOrderByDateAscArray {
			if notDecrementDateNumber == 0 {
				io.Infoln("在[%d]个记录中，ma250单调不递减", originNotDecrementDateNumber)
				return true
			}
			if index == 0 {
				last = averageClosePriceAndMaBetweenDateGroupByDateOrderByDateAsc.AverageMa250
				notDecrementDateNumber--
				continue
			}
			if averageClosePriceAndMaBetweenDateGroupByDateOrderByDateAsc.AverageMa250 > last {
				io.Infoln("在[%d]个记录中，ma250不是单调不递减", originNotDecrementDateNumber)
				return false
			} else {
				last = averageClosePriceAndMaBetweenDateGroupByDateOrderByDateAsc.AverageMa250
				notDecrementDateNumber--
			}
		}

		io.Infoln("默认按照ma250不是单调不递减处理")
		return false
	}
}

// 根据code和date，查找最近8日内的最高收盘价和最低收盘价
func (_stockTransactionDataAllDaoImpl *StockTransactionDataAllDaoImpl) FindHighestAndLowestClosePriceByCodeAndDateInEightDay(code string, date string) domain.MaxHighestPriceAndMinLowestPrice {
	io.Infoln("根据股票代码[%s]]和日期[%s]，查找最近8日内的最高收盘价和最低收盘价", code, date)

	var maxHighestPriceAndMinLowestPrice domain.MaxHighestPriceAndMinLowestPrice
	_stockTransactionDataAllDaoImpl.db.Raw("select max(highest_price) MAX_HIGHEST_PRICE, min(lowest_price) MIN_LOWEST_PRICE "+
		"from (select * from stock_transaction_data_all t where t.code_=? and t.date_<to_date(?, 'yyyy-mm-dd') "+
		"order by t.date_ desc) "+
		"where rownum<=8", code, date).Scan(&maxHighestPriceAndMinLowestPrice)
	return maxHighestPriceAndMinLowestPrice
}

// 随机选取一个股票code
func (_stockTransactionDataAllDaoImpl *StockTransactionDataAllDaoImpl) FindRandomStockCode(beginDate string, enDate string) string {
	io.Infoln("随机选取一个股票code")

	var code string
	var sql string
	if beginDate != "" && enDate != "" {
		sql = "SELECT * FROM (SELECT distinct t.code_ FROM stock_transaction_data_all t " +
			"where (to_date(?,'yyyy-mm-dd')-(SELECT min(t1.date_) FROM stock_transaction_data_all t1 where t1.code_=t.code_))>=500 " +
			"and to_date(?,'yyyy-mm-dd')<=(SELECT max(t2.date_) FROM stock_transaction_data_all t2 where t2.code_=t.code_) " +
			"ORDER BY DBMS_RANDOM.VALUE) WHERE ROWNUM <= 1"
		_stockTransactionDataAllDaoImpl.db.Raw(sql, beginDate, enDate).Scan(&code)
	} else {
		sql = "SELECT * FROM (SELECT distinct t.code_ FROM stock_transaction_data_all t ORDER BY DBMS_RANDOM.VALUE) WHERE ROWNUM <= 1"
		_stockTransactionDataAllDaoImpl.db.Raw(sql).Scan(&code)
	}
	return code
}

// 根据code和date，查询前一个交易日的日期
func (_stockTransactionDataAllDaoImpl *StockTransactionDataAllDaoImpl) FindBeforeOneByStockCodeAndDate(code string, date string) time.Time {
	var beforeDate time.Time
	var sql string = "select t1.date_ from (" +
		"select * from stock_transaction_data_all t where t.code_=? and t.date_<to_date(?,'yyyy-mm-dd') order by t.date_ desc) t1 " +
		"where rownum<=1"
	_stockTransactionDataAllDaoImpl.db.Raw(sql, code, date).Scan(&beforeDate)
	return beforeDate
}

// 查询某个股票的最大日期和最小日期
func (_stockTransactionDataAllDaoImpl *StockTransactionDataAllDaoImpl) FindMinDateAndMaxDate(code string) domain.MaxDataAndMinData {
	io.Infoln("查询某个股票的最大日期和最小日期")

	var mxDataAndMinData domain.MaxDataAndMinData
	_stockTransactionDataAllDaoImpl.db.Table("stock_transaction_data_all").Where("code_=?", code).
		Select("min(date_) MIN_DATE, max(date_) MAX_DATE").Find(&mxDataAndMinData)
	return mxDataAndMinData
}

// 根据code、开始时间和结束时间查询记录，并按照日期升序排列
func (_stockTransactionDataAllDaoImpl *StockTransactionDataAllDaoImpl) FindByCodeBetweenDateOrderByDateAsc(code string, beginDate string, endDate string) model.StockTransactionDataAllArray {
	io.Infoln("根据code[%s]、开始时间[%s]和结束时间[%s]查询记录", code, beginDate, endDate)

	var stockTransactionDataAllArray model.StockTransactionDataAllArray
	_stockTransactionDataAllDaoImpl.db.Raw("select * from stock_transaction_data_all t "+
		"where t.code_=? and t.date_ between to_date(?, 'yyyy-mm-dd') and to_date(?, 'yyyy-mm-dd') "+
		"order by t.date_ asc",
		code, beginDate, endDate).Find(&stockTransactionDataAllArray)
	return stockTransactionDataAllArray
}

// 查询某个股票下一个交易日记录
func (_stockTransactionDataAllDaoImpl *StockTransactionDataAllDaoImpl) FindNextByCodeAndDate(code string, date string) model.StockTransactionDataAll {
	var stockTransactionDataAll model.StockTransactionDataAll
	_stockTransactionDataAllDaoImpl.db.Raw("select * from ("+
		"select * from STOCK_TRANSACTION_DATA_ALL t where t.CODE_=? "+
		"and t.DATE_>to_date(?,'yyyy-mm-dd') order by t.DATE_ asc) t1 where ROWNUM<=1",
		code, date).Find(&stockTransactionDataAll)
	return stockTransactionDataAll
}

// 根据code和date查询股票记录
func (_stockTransactionDataAllDaoImpl *StockTransactionDataAllDaoImpl) FindByCodeAndDate(code string, date string) model.StockTransactionDataAll {
	var stockTransactionDataAll model.StockTransactionDataAll
	_stockTransactionDataAllDaoImpl.db.Raw("select * from STOCK_TRANSACTION_DATA_ALL t where t.CODE_=? "+
		"and t.DATE_=to_date(?,'yyyy-mm-dd')",
		code, date).Find(&stockTransactionDataAll)
	return stockTransactionDataAll
}

// 查询所有code
func (_stockTransactionDataAllDaoImpl *StockTransactionDataAllDaoImpl) FindDistinctCode() []string {
	var codeArray []string
	_stockTransactionDataAllDaoImpl.db.Raw("select distinct t.code_ from STOCK_TRANSACTION_DATA_ALL t").Find(&codeArray)
	return codeArray
}

// 根据date查询上一个交易日的日期
func (_stockTransactionDataAllDaoImpl *StockTransactionDataAllDaoImpl) FindLastDateByDate(date string) *string {
	var _date string
	_stockTransactionDataAllDaoImpl.db.Raw("select distinct to_char(t1.date_, 'yyyy-mm-dd') from ("+
		"select * from STOCK_TRANSACTION_DATA_ALL t where t.date_<to_date(?, 'yyyy-mm-dd') order by t.date_ desc) t1 "+
		"where rownum<=1", date).Find(&_date)
	return &_date
}

// 根据code和date，查询开盘价
func (_stockTransactionDataAllDaoImpl *StockTransactionDataAllDaoImpl) FindOpenPriceByByCodeAndDate(code string, date string) float64 {
	var currentOpenPrice float64
	_stockTransactionDataAllDaoImpl.db.Raw("select t.open_price from stock_transaction_data_all t "+
		"where t.code_ = ? and t.date_ = to_date(?, 'yyyy-mm-dd')",
		code, date).Scan(&currentOpenPrice)
	return currentOpenPrice
}

// 根据code和date，查询上一个交易日的开盘价
func (_stockTransactionDataAllDaoImpl *StockTransactionDataAllDaoImpl) FindLastOpenPriceByByCodeAndDate(code string, date string) float64 {
	var currentOpenPrice float64
	_stockTransactionDataAllDaoImpl.db.Raw("select std.open_price from "+
		"(select * from stock_transaction_data_all t "+
		"where t.code_ = ? and t.date_ < to_date(?, 'yyyy-mm-dd') "+
		"order by t.date_ desc) std where rownum <= 1",
		code, date).Scan(&currentOpenPrice)
	return currentOpenPrice
}

// 根据code和date，查询收盘价
func (_stockTransactionDataAllDaoImpl *StockTransactionDataAllDaoImpl) FindClosePriceByByCodeAndDate(code string, date string) float64 {
	var currentClosePrice float64
	_stockTransactionDataAllDaoImpl.db.Raw("select t.close_price from stock_transaction_data_all t "+
		"where t.code_ = ? and t.date_ = to_date(?, 'yyyy-mm-dd')",
		code, date).Scan(&currentClosePrice)
	return currentClosePrice
}

// 根据code和date，查询上一个交易日的收盘价
func (_stockTransactionDataAllDaoImpl *StockTransactionDataAllDaoImpl) FindLastClosePriceByByCodeAndDate(code string, date string) float64 {
	var currentClosePrice float64
	_stockTransactionDataAllDaoImpl.db.Raw("select std.close_price from "+
		"(select * from stock_transaction_data_all t "+
		"where t.code_ = ? and t.date_ < to_date(?, 'yyyy-mm-dd') "+
		"order by t.date_ desc) std where rownum <= 1",
		code, date).Scan(&currentClosePrice)
	return currentClosePrice
}

// 根据code和date，查询上一个交易日的记录
func (_stockTransactionDataAllDaoImpl *StockTransactionDataAllDaoImpl) FindLastStockTransactionDataAllClosePriceByByCodeAndDate(code string, date string) model.StockTransactionDataAll {
	var stockTransactionDataAll model.StockTransactionDataAll
	_stockTransactionDataAllDaoImpl.db.Raw("select * from "+
		"(select * from stock_transaction_data_all t "+
		"where t.code_ = ? and t.date_ < to_date(?, 'yyyy-mm-dd') "+
		"order by t.date_ desc) std where rownum <= 1",
		code, date).Scan(&stockTransactionDataAll)
	return stockTransactionDataAll
}
